/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.web.formmetadata.i18n.component;

import com.inspur.edp.web.common.customexception.WebCustomException;
import com.inspur.edp.web.common.serialize.SerializeUtility;
import com.inspur.edp.web.common.utility.StringUtility;
import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * 组件处理utility
 *
 * @author noah
 */
public class ComponentUtility {

    ///#region ComponentUtility Singleton

    /**
     * 私有构造函数，避免继承与外部实例化
     */
    private ComponentUtility() {

    }

    private static final ComponentUtility componentUtilityInstance = new ComponentUtility();

    public static ComponentUtility getInstance() {
        return componentUtilityInstance;
    }

    ///#endregion

    ///#region 常量

    private static final String LINE_NUMBER_TITLE = "lineNumberTitle";
    private static final String PLACE_HOLDER = "placeHolder";
    private static final String PLACE_HOLDERCAMEL = "placeholder";
    private static final String CollapseText = "collapseText";
    private static final String ExpandText = "expandText";
    private static final String ControlSource = "controlSource";
    private static final String DIAGLOG_TITLE = "dialogTitle";
    private static final String ENUM_VALUES = "enumValues";
    private static final String CONTROL = "control";
    private static final String ENUM_DATA = "enumData";
    private static final String TAG_DATA = "tagData";
    private static final String NAV_DATA = "navData";
    private static final String EDITOR = "editor";
    private static final String FORMATTER = "formatter";
    private static final String TRUE_TEXT = "trueText";
    private static final String FALSE_TEXT = "falseText";
    private static final String ITEMS = "items";
    private static final String MAIN_TITLE = "mainTitle";
    private static final String SUB_TITLE = "subTitle";
    private static final String PROGRESS_DATA = "progressData";
    private static final String STEP_MESSAGES = "stepMessages";
    private static final String STEP_DATA = "stepData";
    private static final String HEADER_GROUP = "headerGroup";
    private static final String GROUP_TEXT = "groupText";
    private static final String ModalConfig = "modalConfig";
    private static final String Content_Template = "contentTemplate";
    private static final String Toolbar_DATA = "toolbarData";

    private static final String Toolbar = "toolbar";
    ///#endregion

    public <T> T getValue(HashMap<String, Object> component, String keyName) {
        T componentValue = null;

        if (component == null || component.size() == 0) {
            return componentValue;
        }

        Object name = null;
        if (component.containsKey(keyName)) {
            name = component.get(keyName);
        }

        if (name != null) {
            try {
                componentValue = (T) name;
            } catch (RuntimeException e) {
                String componentId = this.getId(component);
                if (StringUtility.isNullOrEmpty(componentId)) {
                    componentId = getType(component);
                    if (StringUtility.isNullOrEmpty(componentId)) {
                        componentId = getName(component);
                    }
                }
                throw new WebCustomException(String.format("Get %1$s's key '%2$s''s Value Failed, Error stack is:", componentId, keyName), e);
            }
        }

        // 如果提取的是字符串 那么将换行符移除掉
        if (componentValue instanceof String) {
            componentValue = (T) StringUtility.removeNewLineParameter((String) componentValue);
        }
        return componentValue;
    }

    public final String getId(HashMap<String, Object> component) {
        return this.getValue(component, "id");
    }
    //vue的type是controlType
    public final String getType(HashMap<String, Object> component) {
        if(StringUtility.isNullOrEmpty(this.getValue(component, "type"))){
            return this.getValue(component, "controlType");
        }else{
            return this.getValue(component, "type");
        }
    }

    public final String getValue(HashMap<String, Object> component) {
        // 兼容value类型是int、double等场景
        return getValueInStr(component, "value");
    }

    /**
     * 根据指定的key获取对应的数值
     *
     * @param component
     * @param key
     * @param backupKey
     * @return
     */

    public final String getValueWithKey(HashMap<String, Object> component, String key, String backupKey) {
        String componentValue = "";
        if (!StringUtility.isNullOrEmpty(key)) {
            // 兼容value类型是int、double等场景
            componentValue = getValueInStr(component, key);
        }

        if (StringUtility.isNullOrEmpty(componentValue) && !StringUtility.isNullOrEmpty(backupKey)) {
            componentValue = getValueInStr(component, backupKey);
        }
        return componentValue;
    }

    /**
     * 根据指定的key获取对应的数值
     *
     * @param component
     * @param key
     * @return
     */

    public final String getValueWithKey(HashMap<String, Object> component, String key) {
        return getValueWithKey(component, key, "");
    }

    public final String getName(HashMap<String, Object> component) {
        return getValueInStr(component, "name");
    }

    private String getValueInStr(HashMap<String, Object> component, String attributeName) {
        if (StringUtility.isNullOrEmpty(attributeName)) {
            return null;
        }
        Object componentNameObject = this.getValue(component, attributeName);
        if (componentNameObject == null) {
            return null;
        }
        if (componentNameObject instanceof Boolean) {
            // 解決布尔类型toString后为True或False问题
            return componentNameObject.toString().toLowerCase();
        } else {
            return componentNameObject.toString();
        }
    }


    public final String getCaption(HashMap<String, Object> component) {
        return this.getValue(component, "caption");
    }

    public final String getCaptionTipContent(HashMap<String, Object> component) {
        return this.getValue(component, "captionTipContent");
    }

    public final String getTitle(HashMap<String, Object> component) {
        return this.getValue(component, "title");
    }

    public final String getMessage(HashMap<String, Object> component) {
        return this.getValue(component, "message");
    }

    public final String getPresetQuerySolutionName(HashMap<String, Object> component) {
        return this.getValue(component, "presetQuerySolutionName");
    }

    public final String getText(HashMap<String, Object> component) {
        return this.getValue(component, "text");
    }

    public final String getHtml(HashMap<String, Object> component) {
        return this.getValue(component, "html");
    }

    public final String getMainTitle(HashMap<String, Object> component) {
        if (!this.checkAndIsString(component, "mainTitle")) {
            return "";
        }
        return this.getValue(component, "mainTitle");
    }

    /**
     * 检测是否是字符串
     *
     * @param component
     * @param key
     * @return
     */
    private boolean checkAndIsString(HashMap<String, Object> component, String key) {
        if (!component.containsKey(key)) {
            return false;
        }
        // 如果不是字符串
        return (component.get(key) instanceof String);
    }

    public final String getMainTitleName() {
        return MAIN_TITLE;
    }

    public final String getSubTitle(HashMap<String, Object> component) {
        if (!this.checkAndIsString(component, "subTitle")) {
            return "";
        }
        return this.getValue(component, "subTitle");
    }

    public final String getSubTitleName() {
        return SUB_TITLE;
    }

    public final String getQueryName(HashMap<String, Object> component) {
        if (!this.checkAndIsString(component, "queryName")) {
            return "";
        }
        return this.getValue(component, "queryName");
    }

    public final HashMap<String, Object> getProgressData(HashMap<String, Object> component) {
        return GetAttributeObject(component, PROGRESS_DATA);
    }

    public final String getProgressDataName(HashMap<String, Object> component) {
        return PROGRESS_DATA;
    }

    public final String getHeaderGroupName(HashMap<String, Object> component) {
        return HEADER_GROUP;
    }

    public final String getFieldRef(HashMap<String, Object> component) {
        return this.getValue(component, "fieldRef");
    }

    public final boolean getCandidateNodeFlag(HashMap<String, Object> component) {
        Boolean componentCandidateNodeFlag = this.<Boolean>getValue(component, "houxunquNode");
        if (componentCandidateNodeFlag == null) {
            componentCandidateNodeFlag = false;
        }
        return componentCandidateNodeFlag;
    }

    public final ArrayList<HashMap<String, Object>> getHeaderGroup(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, HEADER_GROUP);
    }

    /**
     * 获取table的rows节点内容
     *
     * @param component
     * @return
     */
    public final List<HashMap<String, Object>> getRows(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, "rows");
    }


    public final ArrayList<HashMap<String, Object>> getStepMessages(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, STEP_MESSAGES);
    }

    public final ArrayList<HashMap<String, Object>> getStepData(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, STEP_DATA);
    }

    public final String getStepMessagesName(HashMap<String, Object> component) {
        return STEP_MESSAGES;
    }

    public final String getLineNumberTitle(HashMap<String, Object> component) {
        return this.getValue(component, LINE_NUMBER_TITLE);//todo line-number-title
    }

    public final String getInputAppendText(HashMap<String, Object> component) {
        return this.getValue(component, "inputAppendText");
    }

    public final String getGroupText(HashMap<String, Object> component) {
        return this.getValue(component, GROUP_TEXT);
    }

    public final String getUploadSelectText(HashMap<String, Object> component) {
        return this.getValue(component, "uploadSelectText");
    }

    public final String getPreviewDefaultRename(HashMap<String, Object> component) {
        if (!this.checkAndIsString(component, "previewDefaultRename")) {
            return "";
        }
        return this.getValue(component, "previewDefaultRename");
    }

    public final String getAttachCustomInfo(HashMap<String, Object> component) {
        if (!this.checkAndIsString(component, "customInfo")) {
            return "";
        }
        return this.getValue(component, "customInfo");
    }

    public final String getLabel(HashMap<String, Object> component) {
        return this.getValue(component, ComponentNameType.LABEL);
    }

    public List<HashMap<String, Object>> getToolbarData(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, Toolbar_DATA);
    }

    public String getToolbarDataName(HashMap<String, Object> component) {
        return Toolbar_DATA;
    }

    public final String getPlaceHolder(java.util.HashMap<String, Object> component) {
        return getPlaceHolder(component, PLACE_HOLDER);
    }

    public final String getPlaceTitle(HashMap<String, Object> component) {
        return this.getValue(component, "placeTitle");
    }

    public final String getReservationTitle(HashMap<String, Object> component) {
        return this.getValue(component, "reservationTitle");
    }

    public final String getPlaceHolder(HashMap<String, Object> component, String placeHolder) {
        return this.getValue(component, placeHolder);
    }

    public final String getPlaceHolderCamel(HashMap<String, Object> component) {
        return this.getValue(component, PLACE_HOLDERCAMEL);
    }

    public final String getCollapseText(HashMap<String, Object> component) {
        return this.getValue(component, CollapseText);
    }

    public final String getExpandText(HashMap<String, Object> component) {
        return this.getValue(component, ExpandText);
    }

    public List<HashMap<String, Object>> GetFieldsFromContentTemplate(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, "fields");
    }

    public HashMap<String, Object> GetInputGroupModalConfig(HashMap<String, Object> component) {
        return GetAttributeObject(component, "modalConfig");
    }

    public HashMap<String, Object> GetFormatValidation(HashMap<String, Object> component) {
        return GetAttributeObject(component, "formatValidation");
    }


    public ArrayList<HashMap<String, Object>> getDataGridContextMenuItemChildren(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, "children");
    }

    /**
     * controlSource
     *
     * @param component
     * @return
     */
    public final String GetControlSource(HashMap<String, Object> component) {
        return this.getValue(component, ControlSource);
    }

    public final String GetPlaceHolderName(HashMap<String, Object> component) {
        return PLACE_HOLDER;
    }

    public final String getBeginPlaceHolderName(HashMap<String, Object> component) {
        return "beginPlaceHolder";
    }

    public final String getBeginPlaceHolder(java.util.HashMap<String, Object> component) {
        return this.getValue(component, this.getBeginPlaceHolderName(component));
    }

    public final String getEndPlaceHolderName(HashMap<String, Object> component) {
        return "endPlaceHolder";
    }

    public final String getEndPlaceHolder(java.util.HashMap<String, Object> component) {
        return this.getValue(component, this.getEndPlaceHolderName(component));
    }

    public final String getExpandTextName(HashMap<String, Object> component) {
        return ExpandText;
    }

    public final String getCollapseTextName(HashMap<String, Object> component) {
        return CollapseText;
    }


    public final String GetDiaglogTitle(HashMap<String, Object> component) {
        String componentDialogTitle = this.getValue(component, DIAGLOG_TITLE);
        if (StringUtility.isNullOrEmpty(componentDialogTitle)) {
            componentDialogTitle = "";
        }
        return componentDialogTitle;
    }

    public List<HashMap<String, Object>> GetToolbarContentsFromContentTemplate(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, "contents");
    }

    public final String GetDiaglogTitleName(HashMap<String, Object> component) {
        return DIAGLOG_TITLE;
    }

    public final String GetLineNumberTitleName(HashMap<String, Object> component) {
        return LINE_NUMBER_TITLE;
    }

    public final ArrayList<HashMap<String, Object>> GetItems(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, "items");
    }

    public final String GetItemsName(HashMap<String, Object> component) {
        return "items";
    }

    public final ArrayList<HashMap<String, Object>> GetEnumData(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, ENUM_DATA);
    }

    public final ArrayList<HashMap<String, Object>> GetValidationRulesData(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, "validationRules");
    }

    public final String GetEnumDataName(HashMap<String, Object> component) {
        return ENUM_DATA;
    }

    public final ArrayList<HashMap<String, Object>> GetActions(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, "actions");
    }

    public List<HashMap<String, Object>> GetNavData(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, NAV_DATA);
    }

    public String GetNavDataName(HashMap<String, Object> component) {
        return NAV_DATA;
    }

    public final ArrayList<HashMap<String, Object>> GetTagData(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, TAG_DATA);
    }

    public final String GetTagDataName(HashMap<String, Object> component) {
        return TAG_DATA;
    }

    public final ArrayList<HashMap<String, Object>> GetEnumValues(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, ENUM_VALUES);
    }

    public final String GetEnumValuesName(HashMap<String, Object> component) {
        return ENUM_VALUES;
    }

    public final ArrayList<HashMap<String, Object>> GetFieldConfigs(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, "fieldConfigs");
    }


    public ArrayList<HashMap<String, Object>> getDataGridContextMenu(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, "contextMenuItems");
    }
    public ArrayList<HashMap<String, Object>> getColumns(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, "columns");
    }

    public final String getDataGridContextMenuName() {
        return "contextMenuItems";
    }

    public final HashMap<String, String> GetListFilterControl(HashMap<String, Object> component) {
        return this.getValue(component, "control");
    }

    public HashMap<String, Object> getContentTemplate(HashMap<String, Object> component) {
        Object contentTemplate = component.get(Content_Template);

        // 如果内容模板为字符串 那么不进行提取
        if (contentTemplate == null || contentTemplate instanceof String) {
            return null;
        }
        return GetAttributeObject(component, Content_Template);
    }

    public HashMap<String, Object> getPlaceNameTemplate(HashMap<String, Object> component) {
        String placeNameTemplateAttributeName = this.getPlaceNameTemplateAttributeName();
        Object contentTemplate = component.get(placeNameTemplateAttributeName);

        // 如果内容模板为字符串 那么不进行提取
        if (contentTemplate == null || contentTemplate instanceof String) {
            return null;
        }
        return GetAttributeObject(component, placeNameTemplateAttributeName);
    }

    public final String getPlaceNameTemplateAttributeName() {
        return "placeNameTemplate";
    }

    public HashMap<String, Object> getDetailBadgeTemplate(HashMap<String, Object> component) {
        String detailBadgeTemplateAttributeName = this.getDetailBadgeTemplateAttributeName();
        Object contentTemplate = component.get(detailBadgeTemplateAttributeName);

        // 如果内容模板为字符串 那么不进行提取
        if (contentTemplate == null || contentTemplate instanceof String) {
            return null;
        }
        return GetAttributeObject(component, detailBadgeTemplateAttributeName);
    }

    public final String getDetailBadgeTemplateAttributeName() {
        return "detailBadgeTemplate";
    }

    public List<HashMap<String, Object>> getDetailColumns(HashMap<String, Object> component) {
        String detailColumnsAttributeName = this.getDetailColumnsAttributeName();
        Object contentTemplate = component.get(detailColumnsAttributeName);

        // 如果内容模板为字符串 那么不进行提取
        if (contentTemplate == null || contentTemplate instanceof String) {
            return null;
        }
        if (contentTemplate != null && contentTemplate instanceof List) {
            return (List<HashMap<String, Object>>) contentTemplate;
        }
        return null;
        //return GetAttributeObject(component, detailColumnsAttributeName);
    }

    public final String getDetailColumnsAttributeName() {
        return "detailColumns";
    }


    public final ArrayList<HashMap<String, Object>> GetFilterList(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, "filterList");
    }

    public final ArrayList<HashMap<String, Object>> GetToolbarCollection(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, "toolbar");
    }

    public final String GetAggregateTemplate(HashMap<String, Object> component) {
        return this.getValue(component, "aggrTemplate");
    }

    public final String GetAggregateAttributeName(HashMap<String, Object> component) {
        return "aggregate";
    }

    public List<HashMap<String, Object>> GetFooterButtons(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, "footerButtons");
    }

    public final HashMap<String, Object> GetAggregate(HashMap<String, Object> component) {
        return GetAttributeObject(component, "aggregate");
    }

    public final String GetGroupAggregateAttributeName(HashMap<String, Object> component) {
        return "groupAggregate";
    }

    public final HashMap<String, Object> GetGroupAggregate(HashMap<String, Object> component) {
        return GetAttributeObject(component, "groupAggregate");
    }

    public final ArrayList<HashMap<String, Object>> GetEventsCollection(HashMap<String, Object> component) {
        return GetChildComponentCollection(component, "events");
    }


    /**
     * 获取组件中的alt参数值
     *
     * @param component
     * @return
     */
    public final String getAlt(HashMap<String, Object> component) {
        return this.getValue(component, "alt");
    }

    /**
     * 获取标签alt的资源key
     *
     * @return
     */
    public final String getAltAttributeName() {
        return "alt";
    }

    /**
     * 获取imgTitle属性值
     *
     * @param component
     * @return
     */
    public final String getImgTitle(HashMap<String, Object> component) {
        return this.getValue(component, "imgTitle");
    }

    /**
     * 获取imgTitle的资源项key
     *
     * @return
     */
    public final String getImgTitleAttributeName() {
        return "imgTitle";
    }

    public final String GetControlAttributeName(HashMap<String, Object> component) {
        return CONTROL;
    }

    public final HashMap<String, Object> GetControlAttributeObject(HashMap<String, Object> component) {
        return GetAttributeObject(component, CONTROL);
    }

    public final HashMap<String, Object> getModalConfigAttributeObject(HashMap<String, Object> component) {
        return GetAttributeObject(component, ModalConfig);
    }

    public final HashMap<String, Object> GetEditor(HashMap<String, Object> component) {
        return GetAttributeObject(component, EDITOR);
    }

    public final String GetEditorName(HashMap<String, Object> component) {
        return EDITOR;
    }

    public final HashMap<String, Object> GetFormatter(HashMap<String, Object> component) {
        return GetAttributeObject(component, FORMATTER);
    }

    public final String GetFormatterName(HashMap<String, Object> component) {
        return FORMATTER;
    }

    public final String GetTrueText(HashMap<String, Object> component) {
        return this.getValue(component, TRUE_TEXT);
    }

    public final String GetTrueTextName(HashMap<String, Object> component) {
        return TRUE_TEXT;
    }


    public final String GetFalseText(HashMap<String, Object> component) {
        return this.getValue(component, FALSE_TEXT);
    }

    public final String GetFalseTextName(HashMap<String, Object> component) {
        return FALSE_TEXT;
    }

    public final String GetTitleTemplate(HashMap<String, Object> component) {
        return this.getValue(component, "titleTemplate");
    }

    public final HashMap<String, Object> GetToolbar(HashMap<String, Object> component) {
        return GetAttributeObject(component, "toolbar");
    }


    public ArrayList<HashMap<String, Object>> GetCollectionAttributeByName(HashMap<String, Object> component, String attributeName) {
        return this.GetChildComponentCollection(component, attributeName);
    }

    /**
     * 获取当前组件指定属性的子组件集合
     *
     * @param component
     * @param attributeName
     * @return
     */
    private ArrayList<HashMap<String, Object>> GetChildComponentCollection(HashMap<String, Object> component, String attributeName) {
        ArrayList<HashMap<String, Object>> childCompnentCollection = new ArrayList<>();

        Object attributeValue = component.get(attributeName);

        if (attributeValue == null) {
            return childCompnentCollection;
        }

        // 如何从object转换成List<Dictionary<string, object>>
        // https://stackoverflow.com/questions/632570/cast-received-object-to-a-listobject-or-ienumerableobject
        ArrayList<Object> objectCollection = new ArrayList<>((List<Object>) attributeValue);
        for (Object localComponent : objectCollection) {
            // 从object转换成Dictionary<string, object>
            HashMap<String, Object> convertObject = ConvertToDictionaryObject(localComponent);
            childCompnentCollection.add(convertObject);
        }

        return childCompnentCollection;
    }

    /**
     * 获取当前指定属性（对象属性）
     *
     * @param component
     * @param attributeName
     * @return
     */
    public final HashMap<String, Object> GetAttributeObject(HashMap<String, Object> component, String attributeName) {
        HashMap<String, Object> attributeObject = null;

        if (component == null) {
            return attributeObject;
        }

        Object attributeValue = component.get(attributeName);
        if (attributeValue == null) {
            return attributeObject;
        }

        // 从object转换成Dictionary<string, object>
        attributeObject = ConvertToDictionaryObject(attributeValue);
        return attributeObject;
    }

    // 如何从object转换成Dictionary<string, object>
    // https://stackoverflow.com/questions/11576886/how-to-convert-object-to-dictionarytkey-tvalue-in-c
    private HashMap<String, Object> ConvertToDictionaryObject(Object targetObject) {
        String json = SerializeUtility.getInstance().serialize(targetObject, false);
        return SerializeUtility.getInstance().deserialize(json, HashMap.class);
    }
}
